/**
 * Работа с привязками объектов классов
 * Хранит в себе все привязки
 */
app.links = {

    /**
     * Хранит все привязки
     */
    hesh: {},
    
    /**
     * Стандартный объект связи(обычная линия)
     */
    init: {
        unit1Arrow: "empty",
        unit1Text: "",
        unit1Multi: "",
        line: "line_a",
        unit2Text: "",
        unit2Multi: "",
        unit2Arrow: "empty"
    },
    
    /**
     * Строит необходимые объекты для связи
     */
    build: function(id_1) {
        if(this.hesh[id_1] == undefined) {
            this.hesh[id_1] = {};
        }
        if(this.hesh[id_1].link == undefined) {
            this.hesh[id_1].link = {};
        }
    },

    /**
     * Добавляет новые привязки
     *
     * @params {int} unit1 ID
     * @params {int} unit2 ID
     */
    add: function(id_1, id_2) {
        // Строим дерево объектов
        this.build(id_1);
        
        // Если такой связи еще нет
        if(!this.check(id_1, id_2)) {
            this.hesh[id_1].link[id_2] = this.init;
            // Рисуем получившуюся связь
            this.draw(id_1, id_2, this.init);
        }
    },
    
    /**
     * Проверяет связаны классы или нет
     */
    check: function(id_1, id_2) {
        if(typeof this.hesh[id_1].link[id_2] == 'object') {
            return true;
        }
        if(this.hesh[id_2] != undefined) {
            if(this.hesh[id_2].link != undefined) {
                if(typeof this.hesh[id_2].link[id_1] == 'object') {
                    return true;
                }
            }
        }
        return false;
    },
    
    /**
     * Для переданной связи устанавливает новый объект
     */
    set: function(id_1, id_2, link) {
        $("#" + id_1 + "_link_" + id_2).remove();
        this.hesh[id_1].link[id_2] = link;
        this.draw(id_1, id_2, link);
    },
	
    /**
    * Для переданного класса обновляет все связи
    */
    updateAll: function(id) {
        // Ссылка на текущий объект
        var links = this;
        
        this.forId(id, function(id_1, id_2) {
            links.draw(id_1, id_2, links.get(id_1, id_2));
        });
    },
    
    /**
     * Редактирование связи
     */
    edit: function(id_1, id_2){
        // Получаем объект связи
        var link = this.get(id_1, id_2),
        panel = $("#link-edit").attr("id_2", id_2).attr("id_1", id_1);
        panel.children("ul").children("li").removeClass("active");
        panel.children(".unit2.arrows").children("li." + link.unit2Arrow).addClass("active");
        panel.children(".unit2.multi").val(link.unit2Multi);
        panel.children(".unit2.text").val(link.unit2Text);
        panel.children(".line").attr({id_1: id_1, id_2: id_2}).children("li." + link.line).addClass("active");
        panel.children(".unit1.text").val(link.unit1Text);
        panel.children(".unit1.multi").val(link.unit1Multi);
        panel.children(".unit1.arrows").children("li." + link.unit1Arrow).addClass("active");
    },
    
    /**
     * Рисует связь между классаи id_1 и id_2
     */
    draw: function(id_1, id_2, link) {
        // Длинна ширина и центры units
        var centers = (function(unit1, unit2) {
            return {
                unit1: {
                    width: unit1.width(),
                    height: unit1.height(),
                    v: parseInt(unit1.css("left")) + (unit1.width()/2),
                    h: parseInt(unit1.css("top")) + (unit1.height()/2)
                },
                unit2: {
                    width: unit2.width(),
                    height: unit2.height(),
                    v: parseInt(unit2.css("left")) + (unit2.width()/2),
                    h: parseInt(unit2.css("top"))  + (unit2.height()/2)
                }
            };
        }($("#" + id_1), $("#" + id_2))),
        // Ищем необходимые данные для поворота(угол поворота, длинна связи)
        data = this._getRotate(centers),
        // Получаем объект связи
        linkHtml = this._getLink(link, data, centers),
        // Новая связь
        linkHTML = $("<div class='link'></div>").append(linkHtml).attr("id", id_1 + '_link_' + id_2).attr("id_2", id_2).attr("id_1", id_1).addClass(link.line).css({
            left: centers.unit1.v,
            top: centers.unit1.h
        }).css("width", data.width).cssRotate(data.angel);
        // Вставляем новую
        $("#workspace").prepend(linkHTML);
    },
    
    /**
    * Возвращает текст связи в зависимости от объекта связи
    */
    _getLink: function(link, data, centers) {
        // Определяем смещение стрелки относительно объекта и субъекта
        var unit1Shift = this._getShift(data, centers.unit1),
        unit2Shift = this._getShift(data, centers.unit2),
        // Смещение multi относительно центра
        multiOffset = 20,
        // Смещение текста относительно центра
        textOffset = 70,
        turnText = (data.sq == 1 || data.sq == 4) ? " turn" : " top";
        return "\
    <div style='margin-left: " + unit2Shift + "' class='arrow left " + link.unit2Arrow + "'></div>\n\
    <div style='margin-left: " + (unit2Shift + multiOffset) + "' class='multi left" + turnText + "''>" + link.unit2Multi + "</div>\n\
    <div style='margin-left: " + (unit2Shift + textOffset) + "' class='text left" + turnText + "'>" + link.unit2Text + "</div>\n\
    <div class='clickable_link'></div>\n\
    <div style='margin-right: " + (unit1Shift + textOffset) + "' class='text right" + turnText + "'>" + link.unit1Text + "</div>\n\
    <div style='margin-right: " + (unit1Shift + multiOffset) + "' class='multi right" + turnText + "''>" + link.unit1Multi + "</div>\n\
    <div style='margin-right: " + unit1Shift + "' class='arrow right " + link.unit1Arrow + "'></div>";
    },
    
    /**
     * Высчитывает смещение стрелки относительно центра unit так, что она касалась периметра
     */
    _getShift: function(data, center){
        // делим правый верхний часть квадрата на два угла
        var etalon1 = Math.atan(center.width/center.height)*(180/Math.PI),
        etalon2 = 90 - etalon1,
        angel = data.angel + 90,
        height = center.height/2,
        width = center.width/2,
        sections = {
            a: {
                min: 0,
                max: etalon1,
                shift: function(angel) {
                    return height / Math.cos(app.radian(angel));
                }
            },
            b:{
                min: etalon1,
                max: 90,
                shift: function(angel) {
                    return width / Math.cos(app.radian(90-angel));
                }
            },
            c: {
                min: 90,
                max: 90 + etalon2,
                shift: function(angel) {
                    return width / Math.cos(app.radian(angel-90));
                }
            },
            d: {
                min: 90 + etalon2,
                max: 180,
                shift: function(angel) {
                    return height / Math.cos(app.radian(180-angel));
                }
            },
            i: {
                min: 180,
                max: 180 + etalon1,
                shift: function(angel) {
                    return height / Math.cos(app.radian(angel-180));
                }
            },
            f: {
                min: 180 + etalon1,
                max: 270,
                shift: function(angel) {
                    return width / Math.cos(app.radian(270-angel));
                }
            },
            j: {
                min: 270,
                max: 270 + etalon2,
                shift: function(angel) {
                    return width / Math.cos(app.radian(angel-270));
                }
            },
            h: {
                min: 270 + etalon2,
                max: 360,
                shift: function(angel) {
                    return height / Math.cos(app.radian(360-angel));
                }
            }
        };
        // Определяем в какой секции находится связь
        for(i in sections) {
            if(angel >= sections[i].min  && angel <= sections[i].max) {
                return sections[i].shift(angel);
            }
        }
        return 0;
    },
    
    /**
    * Для переданного объекта позиций units возврощает
    * длинну и угол поворота относительно unit1
    */
    _getRotate: function(center) {
        // Номер квадрата
        var sq = (function() {
            // Положение по горизонтали
            var horizontal = (center.unit1.v > center.unit2.v) ? "left" : "right",
            // Положение по вертикали
            vertical = (center.unit1.h > center.unit2.h) ? "up" : "down";

            switch(horizontal + "-" + vertical) {
                case "left-up":
                    return 1;
                case "right-up":
                    return 2;
                case "right-down":
                    return 3;
                case "left-down":
                    return 4;
            }
        } ()),
        // Высота треугольника соеденяющего объект и субъект
        height = Math.abs(center.unit1.h - center.unit2.h),
        // Длинна треугольника соеденяющего объект и субъект
        width = Math.abs(center.unit1.v - center.unit2.v),
        // Угол на который нужно повернуть связь
        angel = (function() {
            // В зависимости от квадрата и тангенса угла находим угол поворота
            switch(sq) {
                case 1:
                    return Math.atan(height/width)*(180/Math.PI)+180;
                case 2:
                    return  Math.atan(width/height)*(180/Math.PI)-90;
                case 3:
                    return  Math.atan(height/width)*(180/Math.PI);
                case 4:
                    var angel = Math.atan(width/height)*(180/Math.PI)+90;
                    return (angel != 0) ? angel : 180;
            }
        } ());
        return {
            // Угол поворота
            angel: angel,
            // Длинна связи (гипотенуза угла)
            width: Math.sqrt(height*height + width*width),
            // Номер квадрата
            sq: sq
        };
    },
    
    /**
     * Возвращает объект для для переданной связи
     */
    get: function(id_1, id_2) {
        return this.hesh[id_1].link[id_2];
    },

    /**
     * Удаляет связь
     */
    del: function(id) {
        var links = this.hesh;
        
        this.forId(id, function(id_1, id_2) {
            $("#" + id_1 + "_link_" + id_2).remove();
            delete links[id_1].link[id_2];
        });
        delete this.hesh[id];
    },
    
    /**
     * Выполняет функцию callback для каждой связи с ID
     * 
     * callback(id_1, id_2);
     */
    forId: function(id, callback) {
        var links = this.hesh;
        
        // Перебираем хранилище
        for(id_1 in links) {
            // Если первый элемент наш ID
            if(id == id_1) {
                // Если есть связи
                if(links[id_1].link != undefined) {
                    // Для каждой связи вызываем callback
                    for(id_2 in links[id_1].link) {
                        callback(id_1, id_2);
                    }
                }
            } else {
                // Если это не первый элемент, ищем во втором
                if(links[id_1].link != undefined) {
                    for(id_2 in links[id_1].link) {
                        if(id_2 == id) {
                            callback(id_1, id_2);
                        }
                    }
                }
            }
        }
    },
	
    /**
     * Удаляет отображение связи
     */
    delView: function(id) {
        this.forId(id, function(id_1, id_2) {
            $("#" + id_1 + "_link_" + id_2).remove();
        });
    }
};